//===- Emulator.cpp - LLVM Emulator Dynamic compiler ----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This utility provides a simple wrapper around the LLVM Execution Engines,
// which allow the direct execution of emulation IR through a Just-In-Time
// compiler.
//
//===----------------------------------------------------------------------===//

#include "../../../cpu/jit.h"
#include "instr.h"
#include "EmulatorInit.h"
#include "EmulatorCompile.h"
#include "EmulatorIRGenerator.h"
#include "EmulatorInterpreter.h"
#include "EmulatorCodeGenerator.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/Type.h"
#include "llvm/Function.h"
#include "llvm/Support/Host.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/CodeGen/LinkAllCodegenComponents.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/ADT/ValueMap.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/ExecutionEngine/JITEventListener.h"
#include "llvm/ExecutionEngine/JITMemoryManager.h"
#include "llvm/Support/TargetSelect.h"
#include <cerrno>
#include <cstdio>

using namespace llvm;


uint64_t bx_asize_mask[] = {
  0xffff,                         // as16 (asize = '00)
  0xffffffff,                     // as32 (asize = '01)
  0xffffffffffffffff,             // as64 (asize = '10)
  0xffffffffffffffff              // as64 (asize = '11)
};

// ========================================
// global objects for easy access. 
// ========================================
Module                *EmuModule = 0;
ExecutionEngine       *EmuEE = 0;
EmulatorIRGenerator   *EmuIRGen = 0;
EmulatorCodeGenerator *EmuCodeGen = 0;
EmulatorInterpreter   *EmuInterp = 0;

// All the functions that have been emitted.
std::map<void*, Function *> EmittedFunctions;

EmulatorIRGenerator* getGlobalIRGen(void) { return EmuIRGen; }
EmulatorCodeGenerator* getGlobalCodeGen(void) { return EmuCodeGen; }
EmulatorInterpreter* getGlobalInterp(void) { return EmuInterp; }
Module * getGlobalModule(void) { return EmuModule; }
ExecutionEngine* getGlobalEE(void) { return EmuEE; }


// ========================================
// Hooks for the interpreter. 
// ========================================
extern "C" void* compile(void* ibegin, void* iend, void* BochsCall)
{
  // ========================================
  // step 1. initialize a compilation unit. 
  // ========================================
  Function *current = getCompilationUnit();

  // ========================================
  // step 2. generate LLVM IR tree.
  // ========================================
  generateInstructionIR(current, ibegin, iend);

  // ========================================
  // step 3. generate native code.
  // ========================================
  void *Addr=getGlobalEE()->getPointerToFunction(current); 
  EmittedFunctions[Addr] = current; 
  return Addr;
}

extern "C" void initializeEmulatorJIT(void) 
{
  // ========================================
  // initialize the emulator module. 
  // ========================================
  EmuModule = initializeModule();
 
  // ========================================
  // initialize the emulator execution engine. 
  // ========================================
  EmuEE = initializeExecutionEngine(); 

  // ========================================
  // initialize the emulator interpreter. 
  // ========================================
  EmuInterp = initializeInterpreter();

  // ========================================
  // initialize the emulator IR generator. 
  // ========================================
  EmuIRGen = initializeIRGenerator(); 

  // ========================================
  // initialize the emulator native code snippets. 
  // ========================================
  EmuCodeGen = initializeCodeGenerator();
}

extern "C" void initializeEmulatorSnippet(BX_JIT_C* snippets)
{
  snippets->comp_code_cache_entry = getGlobalCodeGen()->getJITEntryRoutine();
  snippets->comp_code_cache_exit  = getGlobalCodeGen()->getJITExitRoutine();
}

extern "C" void initializeInterpreterCallbacks(inp_callbacks *cbs)
{
  getGlobalInterp()->interpret = cbs->interpret;
  getGlobalInterp()->naked_interpret = cbs->naked_interpret;
  getGlobalInterp()->resolve_modrm  = cbs->resolve_modrm;
  getGlobalInterp()->modrm_xlation  = cbs->modrm_xlation;
  getGlobalInterp()->find_field_offset_by_name = cbs->find_field_offset_by_name;
  getGlobalInterp()->find_reg_offset_by_index  = cbs->find_reg_offset_by_index;
  getGlobalInterp()->initializeFieldOffset();
}

extern "C" void invalidateCompilation(void* Addr) 
{
  std::map<void *, Function *>::iterator Emitted = EmittedFunctions.find(Addr);
  if (Emitted != EmittedFunctions.end()) 
  {
    // Invalidate a compiled unit.
    EmuEE->deallocateMemForFunction(Emitted->second);
    EmittedFunctions.erase(Emitted);
  }
}

 
  
